#include "expressionengine_mt.h"

#include <bool.h>
#include <boolproxy.h>
#include <bstring.h>
#include <bstringproxy.h>
#include <dynamictypemanager.h>
#include <expression.h>
#include <expressionengine.h>
#include <expressionvalidator.h>
#include <multiset.h>
#include <multisetproxy.h>
#include <number.h>
#include <numberproxy.h>
#include <timedmultiset.h>
#include <timedmultisetproxy.h>
#include <typefactory.h>
#include <wfnet.h>

#include <QtTest/QTest>

using namespace wfnet;
using namespace moduletest;

void ExpressionEngine_mt::initTestCase()
{
    Bool boolean;
    BasicString string;
    Number number;

    m_net = new WfNet(this);

    DynamicTypeManager::getInstance()->registerColorSet(
        "Booleans", boolean, m_net);
    DynamicTypeManager::getInstance()->registerColorSet(
        "Strings", string, m_net);
    DynamicTypeManager::getInstance()->registerColorSet(
        "Numbers", number, m_net);
    DynamicTypeManager::getInstance()->registerColorSet(
        "NumbersTimed", number, m_net, true);

    DynamicTypeManager::getInstance()->registerVariable(
        "b", "Booleans", m_net);

    DynamicTypeManager::getInstance()->registerVariable(
        "s", "Strings", m_net);
    DynamicTypeManager::getInstance()->registerVariable(
        "t", "Strings", m_net);

    DynamicTypeManager::getInstance()->registerVariable(
        "n", "Numbers", m_net);
    DynamicTypeManager::getInstance()->registerVariable(
        "k", "Numbers", m_net);

    ExpressionValidator::getInstance()->registerKeywordMasks(
        TypeFactory::getInstance()->registeredKeywordMasks());

    ExpressionEngine::getInstance()->registerTypeProxy(Bool::NAME,
        BoolProxy::NAME);
    ExpressionEngine::getInstance()->registerTypeProxy(BasicString::NAME,
        BasicStringProxy::NAME);
    ExpressionEngine::getInstance()->registerTypeProxy(Number::NAME,
        NumberProxy::NAME);
    ExpressionEngine::getInstance()->registerTypeProxy(Multiset::NAME,
        MultisetProxy::NAME);
    ExpressionEngine::getInstance()->registerTypeProxy(TimedMultiset::NAME,
        TimedMultisetProxy::NAME);
}

void ExpressionEngine_mt::eval()
{
    QFETCH(bool, value);
    QFETCH(bool, result);

    QCOMPARE(value, result);

    //QBENCHMARK {}
}

void ExpressionEngine_mt::eval_data()
{
    QTest::addColumn<bool>("value");
    QTest::addColumn<bool>("result");

    // valid
    Expression* expression = dynamic_cast<Expression *>(
        m_net->addExpression("b", "Booleans"));

    Binding binding;
    binding.addBoundVariable("b", Bool(true));
    expression->setBinding(binding);
    binding.clear();
    ValueType* value = dynamic_cast<ValueType* >(expression->eval());

    QTest::newRow("b") << (value->getValue().toBool() == true) << true;
    delete value;

    expression = dynamic_cast<Expression *>(
        m_net->addExpression("b == true", "Booleans"));

    binding.addBoundVariable("b", Bool(true));
    expression->setBinding(binding);
    binding.clear();
    value = dynamic_cast<ValueType* >(expression->eval());

    QTest::newRow("b == true") << (value->getValue().toBool() == true) << true;
    delete value;

    expression = dynamic_cast<Expression *>(
        m_net->addExpression("((n + 1) + k) + (n + (k - 5))", "Numbers"));

    binding.addBoundVariable("n", Number(2));
    binding.addBoundVariable("k", Number(4));
    expression->setBinding(binding);
    binding.clear();
    value = dynamic_cast<ValueType* >(expression->eval());

    QTest::newRow("((n + 1) + k) + (n + (k - 5))") <<
    (value->getValue().toInt() == 8) << true;
    delete value;

    expression = dynamic_cast<Expression *>(
        m_net->addExpression("{2*n}", "Numbers"));

    binding.addBoundVariable("n", Number(2));
    expression->setBinding(binding);
    binding.clear();
    Multiset* mt = dynamic_cast<Multiset* >(expression->eval());

    QTest::newRow("{2*n}") <<
        (mt->toValue() == "{2*2}") << true;
    delete mt;

    expression = dynamic_cast<Expression *>(
        m_net->addExpression("{2*5@10}", "NumbersTimed", nid(), true));

    expression->setBinding(binding);
    binding.clear();
    TimedMultiset* tmt = dynamic_cast<TimedMultiset* >(expression->eval());

    QTest::newRow("{2*5@10}") <<
        (tmt->toValue() == "{2*5@10}") << true;
    delete tmt;
}

void ExpressionEngine_mt::cleanupTestCase()
{
    DynamicTypeManager::getInstance()->unregisterColorSet("Booleans",
        m_net);
    DynamicTypeManager::getInstance()->unregisterColorSet("Strings",
        m_net);
    DynamicTypeManager::getInstance()->unregisterColorSet("Numbers",
        m_net);
    DynamicTypeManager::getInstance()->unregisterVariable("b", m_net);
    DynamicTypeManager::getInstance()->unregisterVariable("s", m_net);
    DynamicTypeManager::getInstance()->unregisterVariable("t", m_net);
    DynamicTypeManager::getInstance()->unregisterVariable("n", m_net);
    DynamicTypeManager::getInstance()->unregisterVariable("k", m_net);

    ExpressionValidator::getInstance()->clearKeywordMasks();

    ExpressionEngine::getInstance()->unregisterTypeProxy(Bool::NAME);
    ExpressionEngine::getInstance()->unregisterTypeProxy(BasicString::NAME);
    ExpressionEngine::getInstance()->unregisterTypeProxy(Number::NAME);
    ExpressionEngine::getInstance()->unregisterTypeProxy(Multiset::NAME);
    ExpressionEngine::getInstance()->unregisterTypeProxy(TimedMultiset::NAME);
}
